<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CPU核心使用率监控系统</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/luxon@3.0.1"></script>
    <script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-luxon@1.2.0"></script>
    <style>
        :root {
            --primary: #4361ee;
            --warning: #f8961e;
            --danger: #ef233c;
            --success: #2ec4b6;
            --dark: #2b2d42;
        }

        body {
            background-color: #f8f9fa;
            font-family: 'Segoe UI', system-ui, sans-serif;
        }

        .dashboard-header {
            background: linear-gradient(135deg, var(--dark) 0%, var(--primary) 100%);
            color: white;
            padding: 1.5rem 0;
            margin-bottom: 2rem;
            box-shadow: 0 4px 6px rgba(0,0,0,0.1);
        }

        .analysis-card {
            border-radius: 10px;
            margin-bottom: 2rem;
            box-shadow: 0 4px 6px rgba(0,0,0,0.05);
            background: white;
        }

        .chart-container {
            position: relative;
            height: 400px;
            margin-bottom: 1rem;
        }

        .host-selector {
            max-width: 300px;
        }

        .core-selector {
            max-width: 300px;
        }

        .time-slider {
            width: 100%;
        }

        .filter-controls {
            background: white;
            padding: 1rem;
            border-radius: 8px;
            margin-bottom: 1rem;
            box-shadow: 0 2px 4px rgba(0,0,0,0.05);
        }

        .host-group {
            border-left: 3px solid #dee2e6;
            padding-left: 10px;
            margin-bottom: 10px;
        }

        .host-check {
            margin-right: 8px;
        }

        .core-check {
            margin-right: 5px;
        }

        .alert-no-data {
            margin-top: 1rem;
        }
    </style>
</head>
<body>
    <div class="dashboard-header">
        <div class="container">
            <h1><i class="bi bi-cpu"></i> CPU核心使用率监控系统</h1>
            <p class="mb-0">主机与核心使用率时空分析</p>
        </div>
    </div>

    <div class="container">
        <!-- 控制面板 -->
        <div class="filter-controls">
            <div class="row g-3">
                <div class="col-md-4">
                    <label for="hostSelector" class="form-label">主机名</label>
                    <select class="form-select host-selector" id="hostSelector">
                        <option value="">所有主机</option>
                        <!-- 选项将通过JavaScript动态生成 -->
                    </select>
                </div>
                <div class="col-md-4">
                    <label for="coreSelector" class="form-label">CPU核心</label>
                    <select class="form-select core-selector" id="coreSelector">
                        <option value="">所有核心</option>
                        <!-- 选项将通过JavaScript动态生成 -->
                    </select>
                </div>
                <div class="col-md-4">
                    <label for="timeRange" class="form-label">时间范围</label>
                    <input type="range" class="form-range time-slider" id="timeRange" min="0" max="100" value="100">
                    <div id="timeRangeValue" class="small text-muted">全部时间</div>
                </div>
            </div>
        </div>

        <!-- 数据状态提示 -->
        <div id="dataStatus" class="alert alert-warning alert-no-data d-none">
            <i class="bi bi-exclamation-triangle"></i> 当前没有可用的CPU数据或数据加载异常
        </div>

        <!-- CPU使用率热力图 -->
        <div class="analysis-card">
            <div class="card-header d-flex justify-content-between align-items-center">
                <h5 class="card-title mb-0"><i class="bi bi-grid-3x3"></i> CPU核心使用率时空热力图</h5>
                <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" id="stackToggle" checked>
                    <label class="form-check-label" for="stackToggle">堆叠显示</label>
                </div>
            </div>
            <div class="card-body">
                <div class="chart-container">
                    <canvas id="heatmapChart"></canvas>
                </div>
            </div>
        </div>

        <!-- CPU使用趋势图 -->
        <div class="analysis-card">
            <div class="card-header">
                <div class="d-flex justify-content-between align-items-center">
                    <h5 class="card-title mb-0"><i class="bi bi-graph-up"></i> CPU核心使用趋势</h5>
                    <div id="hostLegend" class="d-flex flex-wrap gap-2"></div>
                </div>
            </div>
            <div class="card-body">
                <div class="chart-container">
                    <canvas id="trendChart"></canvas>
                </div>
            </div>
        </div>
    </div>

    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
    <script>
        // 图表实例
        let heatmapChart, trendChart;
        let processedData = null;

        // 示例数据 - 包含flask和am两个主机
        const sampleData = {
            "code": 0,
            "msg": "get cpu info success",
            "data": [
                {
                    "id": 1,
                    "hostname": "flask",
                    "date": "2025-08-06 11:14:36",
                    "cpu_core": "cpu0",
                    "cpu_used": "45.0%",
                    "cpu_free": "55.0%"
                },
                {
                    "id": 2,
                    "hostname": "flask",
                    "date": "2025-08-06 11:14:36",
                    "cpu_core": "cpu1",
                    "cpu_used": "50.0%",
                    "cpu_free": "50.0%"
                },
                {
                    "id": 3,
                    "hostname": "am",
                    "date": "2025-08-06 12:01:14",
                    "cpu_core": "cpu0",
                    "cpu_used": "40.8%",
                    "cpu_free": "59.2%"
                },
                {
                    "id": 4,
                    "hostname": "am",
                    "date": "2025-08-06 12:01:14",
                    "cpu_core": "cpu1",
                    "cpu_used": "24.2%",
                    "cpu_free": "75.8%"
                }
            ]
        };

        // 初始化页面
        document.addEventListener('DOMContentLoaded', async function() {
            try {
                // 模拟API调用 - 实际使用时替换为真实API调用
                const response = await fetchCPUData();

                if (response.code !== 0 || !response.data || response.data.length === 0) {
                    showDataStatus(true);
                    return;
                }

                showDataStatus(false);

                // 处理原始数据
                const rawData = response.data.map(item => {
                    return {
                        ...item,
                        cpu_used: parseFloat(item.cpu_used.replace('%', '')) || 0,
                        timestamp: new Date(item.date).getTime()
                    };
                });

                // 处理数据
                processedData = processData(rawData);
                console.log("处理后的数据:", processedData);

                // 初始化UI组件
                initSelectors();
                initHeatmap();
                initTrendChart();

                // 初始化事件监听
                initEventListeners();

            } catch (error) {
                console.error("初始化失败:", error);
                showDataStatus(true);
            }
        });

        // 模拟API调用
        async function fetchCPUData() {
            // 这里应该是您的API调用代码
            // 返回示例数据
            return sampleData;
        }

        // 数据处理
        function processData(rawData) {
            const hosts = [...new Set(rawData.map(item => item.hostname))];
            const cores = [...new Set(rawData.map(item => item.cpu_core))];
            const timestamps = [...new Set(rawData.map(item => item.date))].sort((a, b) => new Date(a) - new Date(b));

            // 构建数据矩阵
            const matrix = {};
            hosts.forEach(host => {
                matrix[host] = {};
                cores.forEach(core => {
                    matrix[host][core] = {};
                    timestamps.forEach(time => {
                        const record = rawData.find(
                            item => item.hostname === host &&
                                  item.cpu_core === core &&
                                  item.date === time
                        );
                        matrix[host][core][time] = record || null;
                    });
                });
            });

            return {
                hosts,
                cores,
                timestamps,
                matrix,
                minDate: new Date(timestamps[0]),
                maxDate: new Date(timestamps[timestamps.length - 1])
            };
        }

        // 显示/隐藏数据状态提示
        function showDataStatus(show) {
            const statusElement = document.getElementById('dataStatus');
            if (show) {
                statusElement.classList.remove('d-none');
                document.querySelectorAll('.analysis-card').forEach(card => {
                    card.classList.add('d-none');
                });
            } else {
                statusElement.classList.add('d-none');
                document.querySelectorAll('.analysis-card').forEach(card => {
                    card.classList.remove('d-none');
                });
            }
        }

        // 初始化筛选器选项
        function initSelectors() {
            const hostSelector = document.getElementById('hostSelector');
            const coreSelector = document.getElementById('coreSelector');

            // 清空现有选项
            while (hostSelector.options.length > 1) hostSelector.remove(1);
            while (coreSelector.options.length > 1) coreSelector.remove(1);

            // 添加主机选项
            processedData.hosts.forEach(host => {
                const option = document.createElement('option');
                option.value = host;
                option.textContent = host;
                hostSelector.appendChild(option);
            });

            // 添加核心选项
            processedData.cores.forEach(core => {
                const option = document.createElement('option');
                option.value = core;
                option.textContent = core;
                coreSelector.appendChild(option);
            });
        }

        // 初始化热力图
        function initHeatmap() {
            const ctx = document.getElementById('heatmapChart');
            if (!ctx) return;

            const datasets = [];
            processedData.hosts.forEach((host, hostIdx) => {
                processedData.cores.forEach((core, coreIdx) => {
                    const color = `hsl(${(hostIdx * 30 + coreIdx * 10) % 360}, 70%, 50%)`;
                    const dataPoints = processedData.timestamps.map(time => {
                        const val = processedData.matrix[host][core][time]?.cpu_used;
                        return val !== undefined ? {
                            x: time,
                            y: val,
                            host: host,
                            core: core
                        } : null;
                    }).filter(Boolean);

                    if (dataPoints.length > 0) {
                        datasets.push({
                            label: `${host} - ${core}`,
                            data: dataPoints,
                            backgroundColor: color,
                            borderColor: color,
                            borderWidth: 1,
                            host: host,
                            core: core,
                            hidden: false
                        });
                    }
                });
            });

            // 销毁旧图表实例
            if (heatmapChart) {
                heatmapChart.destroy();
            }

            heatmapChart = new Chart(ctx, {
                type: 'bar',
                data: {
                    datasets: datasets
                },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    scales: {
                        x: {
                            type: 'time',
                            time: {
                                parser: 'yyyy-MM-dd HH:mm:ss',
                                tooltipFormat: 'MM-dd HH:mm',
                                unit: 'minute'
                            },
                            stacked: document.getElementById('stackToggle').checked,
                            title: { display: true, text: '时间' }
                        },
                        y: {
                            min: 0,
                            max: 100,
                            stacked: document.getElementById('stackToggle').checked,
                            title: { display: true, text: '使用率 (%)' }
                        }
                    },
                    plugins: {
                        tooltip: {
                            callbacks: {
                                label: function(context) {
                                    return `${context.dataset.label}: ${context.parsed.y}%`;
                                },
                                afterLabel: function(context) {
                                    const data = context.dataset.data[context.dataIndex];
                                    if (data && data.host && data.core) {
                                        const record = processedData.matrix[data.host][data.core][data.x];
                                        if (record) {
                                            return `时间: ${data.x}\n主机: ${data.host}\n核心: ${data.core}`;
                                        }
                                    }
                                    return '';
                                }
                            }
                        }
                    },
                    onClick: function(_, elements) {
                        if (elements.length > 0) {
                            const element = elements[0];
                            const dataset = this.data.datasets[element.datasetIndex];
                            const data = dataset.data[element.index];
                            filterData(dataset.host, dataset.core, data.x);
                        }
                    }
                }
            });
        }

        // 初始化趋势图
        function initTrendChart() {
            const ctx = document.getElementById('trendChart');
            if (!ctx) return;

            const datasets = [];
            const legendContainer = document.getElementById('hostLegend');
            legendContainer.innerHTML = '';

            // 按主机分组创建数据集
            processedData.hosts.forEach((host, hostIdx) => {
                processedData.cores.forEach((core, coreIdx) => {
                    const color = `hsl(${(hostIdx * 30 + coreIdx * 10) % 360}, 70%, 50%)`;
                    const dataPoints = processedData.timestamps.map(time => {
                        const val = processedData.matrix[host][core][time]?.cpu_used;
                        return val !== undefined ? { x: time, y: val } : null;
                    }).filter(Boolean);

                    if (dataPoints.length > 0) {
                        const datasetId = `${host}-${core}`.replace(/\s+/g, '-');
                        datasets.push({
                            id: datasetId,
                            label: `${host} - ${core}`,
                            data: dataPoints,
                            borderColor: color,
                            backgroundColor: color + '20',
                            tension: 0.3,
                            fill: true,
                            borderWidth: 2,
                            pointRadius: 3,
                            pointHoverRadius: 5,
                            hidden: false
                        });
                    }
                });
            });

            // 销毁旧图表实例
            if (trendChart) {
                trendChart.destroy();
            }

            trendChart = new Chart(ctx, {
                type: 'line',
                data: { datasets: datasets },
                options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    interaction: {
                        intersect: false,
                        mode: 'index'
                    },
                    scales: {
                        x: {
                            type: 'time',
                            time: {
                                parser: 'yyyy-MM-dd HH:mm:ss',
                                tooltipFormat: 'MM-dd HH:mm',
                                unit: 'minute'
                            },
                            title: { display: true, text: '时间' },
                            min: processedData.minDate,
                            max: processedData.maxDate
                        },
                        y: {
                            min: 0,
                            max: 100,
                            title: { display: true, text: '使用率 (%)' }
                        }
                    },
                    plugins: {
                        tooltip: {
                            callbacks: {
                                label: function(context) {
                                    return `${context.dataset.label}: ${context.parsed.y}%`;
                                },
                                afterLabel: function(context) {
                                    const time = context.parsed.x;
                                    const labelParts = context.dataset.label.split(' - ');
                                    if (labelParts.length === 2) {
                                        return `时间: ${time}\n主机: ${labelParts[0]}\n核心: ${labelParts[1]}`;
                                    }
                                    return '';
                                }
                            }
                        }
                    }
                }
            });

            // 初始化图例
            updateLegendStates('', '');
        }

        // 筛选数据
        function filterData(host, core, time) {
            // 更新筛选器UI
            if (host !== undefined) {
                document.getElementById('hostSelector').value = host || '';
            }
            if (core !== undefined) {
                document.getElementById('coreSelector').value = core || '';
            }

            // 更新图表可见性
            updateChartVisibility(host, core);
        }

        // 更新图表可见性
        function updateChartVisibility(host, core) {
            // 更新热力图
            if (heatmapChart) {
                heatmapChart.data.datasets.forEach(dataset => {
                    const shouldShow =
                        (!host || dataset.host === host) &&
                        (!core || dataset.core === core);

                    dataset.hidden = !shouldShow;
                });
                heatmapChart.update();
            }

            // 更新趋势图
            if (trendChart) {
                trendChart.data.datasets.forEach(dataset => {
                    const [datasetHost, datasetCore] = dataset.label.split(' - ');
                    const shouldShow =
                        (!host || datasetHost === host) &&
                        (!core || datasetCore === core);

                    dataset.hidden = !shouldShow;
                });
                trendChart.update();
            }

            // 更新图例状态
            updateLegendStates(host, core);
        }

        // 更新图例状态
        function updateLegendStates(host, core) {
            const legendContainer = document.getElementById('hostLegend');
            legendContainer.innerHTML = '';

            // 按主机分组创建图例
            processedData.hosts.forEach((hostName, hostIdx) => {
                const hostGroup = document.createElement('div');
                hostGroup.className = 'host-group';

                // 主机复选框
                const hostHeader = document.createElement('div');
                hostHeader.className = 'd-flex align-items-center mb-1';

                const hostCheckbox = document.createElement('input');
                hostCheckbox.type = 'checkbox';
                hostCheckbox.className = 'form-check-input host-check me-2';
                hostCheckbox.id = `host-${hostName}`;
                hostCheckbox.dataset.host = hostName;

                // 检查该主机是否应该显示
                const hostShouldShow = !host || hostName === host;
                hostCheckbox.checked = hostShouldShow;

                hostHeader.appendChild(hostCheckbox);

                const hostLabel = document.createElement('label');
                hostLabel.className = 'form-check-label fw-bold';
                hostLabel.htmlFor = `host-${hostName}`;
                hostLabel.textContent = hostName;
                hostHeader.appendChild(hostLabel);

                hostGroup.appendChild(hostHeader);

                // 核心复选框容器
                const coresContainer = document.createElement('div');
                coresContainer.className = 'd-flex flex-wrap gap-2 ms-3';

                // 为该主机添加核心复选框
                processedData.cores.forEach((coreName, coreIdx) => {
                    const coreId = `${hostName}-${coreName}`.replace(/\s+/g, '-');
                    const color = `hsl(${(hostIdx * 30 + coreIdx * 10) % 360}, 70%, 50%)`;

                    const coreItem = document.createElement('div');
                    coreItem.className = 'form-check form-check-inline';

                    const coreCheckbox = document.createElement('input');
                    coreCheckbox.type = 'checkbox';
                    coreCheckbox.className = 'form-check-input core-check me-1';
                    coreCheckbox.id = `core-${coreId}`;
                    coreCheckbox.dataset.host = hostName;
                    coreCheckbox.dataset.core = coreName;

                    // 检查该核心是否应该显示
                    const coreShouldShow = hostShouldShow && (!core || coreName === core);
                    coreCheckbox.checked = coreShouldShow;

                    coreItem.appendChild(coreCheckbox);

                    const coreLabel = document.createElement('label');
                    coreLabel.className = 'form-check-label small';
                    coreLabel.htmlFor = `core-${coreId}`;
                    coreLabel.textContent = coreName;
                    coreLabel.style.color = color;
                    coreItem.appendChild(coreLabel);

                    coresContainer.appendChild(coreItem);
                });

                hostGroup.appendChild(coresContainer);
                legendContainer.appendChild(hostGroup);
            });

            // 主机复选框事件
            document.querySelectorAll('.host-check').forEach(checkbox => {
                checkbox.addEventListener('change', function() {
                    const host = this.dataset.host;
                    const isChecked = this.checked;

                    // 更新该主机下所有核心的复选框状态
                    document.querySelectorAll(`.core-check[data-host="${host}"]`).forEach(coreCheck => {
                        coreCheck.checked = isChecked;
                    });

                    // 更新筛选器
                    document.getElementById('hostSelector').value = isChecked ? host : '';
                    document.getElementById('coreSelector').value = '';

                    // 更新图表
                    updateChartVisibility(isChecked ? host : '', '');
                });
            });

            // 核心复选框事件
            document.querySelectorAll('.core-check').forEach(checkbox => {
                checkbox.addEventListener('change', function() {
                    const host = this.dataset.host;
                    const core = this.dataset.core;

                    // 检查该主机下是否有选中的核心
                    const anyCoreSelected = Array.from(
                        document.querySelectorAll(`.core-check[data-host="${host}"]`)
                    ).some(c => c.checked);

                    // 更新主机复选框状态
                    const hostCheckbox = document.querySelector(`.host-check[data-host="${host}"]`);
                    hostCheckbox.checked = anyCoreSelected;
                    hostCheckbox.indeterminate = anyCoreSelected &&
                        !Array.from(document.querySelectorAll(`.core-check[data-host="${host}"]`))
                            .every(c => c.checked);

                    // 更新筛选器
                    document.getElementById('hostSelector').value = host;
                    document.getElementById('coreSelector').value = this.checked ? core : '';

                    // 更新图表
                    updateChartVisibility(host, this.checked ? core : '');
                });
            });
        }

        // 初始化事件监听
        function initEventListeners() {
            // 主机选择器事件
            document.getElementById('hostSelector').addEventListener('change', function() {
                const host = this.value;
                filterData(host, '');
            });

            // 核心选择器事件
            document.getElementById('coreSelector').addEventListener('change', function() {
                const core = this.value;
                const host = document.getElementById('hostSelector').value;
                filterData(host, core);
            });

            // 堆叠显示切换
            document.getElementById('stackToggle').addEventListener('change', function() {
                if (heatmapChart) {
                    heatmapChart.options.scales.x.stacked = this.checked;
                    heatmapChart.options.scales.y.stacked = this.checked;
                    heatmapChart.update();
                }
            });

            // 时间范围滑块
            document.getElementById('timeRange').addEventListener('input', function() {
                const percent = parseInt(this.value);
                const timeDiff = processedData.maxDate - processedData.minDate;
                const newMinDate = new Date(processedData.minDate.getTime() + timeDiff * percent / 100);

                if (trendChart) {
                    trendChart.options.scales.x.min = newMinDate;
                    trendChart.update();
                }

                document.getElementById('timeRangeValue').textContent =
                    percent === 100 ? '全部时间' : `最近 ${100 - percent}% 时间范围`;
            });
        }
    </script>
</body>
</html>